package com.smilive.start.netty.jdk;

import com.smilive.start.netty.utils.ByteBufferUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @program: netty_start
 * @Date: 2022-01-04 14:46
 * @Author: smilive
 * @Description:
 */
@Slf4j
public class NetSelectorServer {

    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(16);
        try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()){
            serverSocketChannel.bind(new InetSocketAddress(8000));
            serverSocketChannel.configureBlocking(false);
            //创建选择器
            Selector selector = Selector.open();

            //将通道注册到选择器,并设置监听事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

            while (true){
                // 若没有事件就绪，线程会被阻塞，反之不会被阻塞。从而避免了CPU空转
                // 返回值为就绪的事件个数
                int ready = selector.select();
                log.debug("监听事件个数:{}",ready);
                //获取所有监听事件
                Set<SelectionKey> selectionKeys = selector.selectedKeys();

                Iterator<SelectionKey> iterator = selectionKeys.iterator();
                while (iterator.hasNext()){
                    SelectionKey selectionKey = iterator.next();

                    //判断可以类型
                    if (selectionKey.isAcceptable()) {
                        // 获得key对应的channel
                        ServerSocketChannel channel = (ServerSocketChannel)selectionKey.channel();
                        SocketChannel socketChannel = channel.accept();
                        log.debug("建立连接:{}",socketChannel);
                        //设置为非阻塞模式，
                        socketChannel.configureBlocking(false);
                        //将连接的通道也注册到选择其中
                        socketChannel.register(selector,SelectionKey.OP_READ);
                        iterator.remove();
                    }
                    if (selectionKey.isReadable()) {
                        // 获得key对应的channel
                        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                        log.debug("读取数据:{}",socketChannel);
                        socketChannel.read(byteBuffer);
                        byteBuffer.flip();
                        ByteBufferUtil.debugAll(byteBuffer);
                        byteBuffer.clear();
                        iterator.remove();
                    }
                }

            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
